package com.xiaomaoguai.fcp.pre.kepler.router.rpc.server.servlet.core;

import com.xiaomaoguai.fcp.pre.kepler.router.rpc.constants.HttpConstants;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.enums.Protocol;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.exception.NettyServerException;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.options.ServerOptions;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.server.channelInitializer.HandlerInitSelector;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.server.channelInitializer.NettyChannelInitializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ClassUtils;
import javax.servlet.ServletException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Random;

/**
 * Spring Boot2.0会查找WebServerFactory接口的实现类(工厂类)，调用其getWebServer()方法，来获取web应用的容器
 * 通过继承AbstractServletWebServerFactory类来实现
 *
 * @author DH
 */
public class EmbeddedNettyFactory extends AbstractServletWebServerFactory implements ResourceLoaderAware {


	@Value("${server.nettyServlet.nProcessors}")
	private Integer nProcessors;

	@Value("${server.nettyServlet.timeout}")
	private Integer timeout;

	private ResourceLoader resourceLoader;

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

	@Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		ClassLoader parentClassLoader = resourceLoader != null ? resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader();
		//是否支持默认Servlet
		if (isRegisterDefaultServlet()) {
			logger.warn("This container does not support a default servlet");
		}
		//上下文
		NettyContext context = new NettyContext(getContextPath(), new URLClassLoader(new URL[]{}, parentClassLoader), HttpConstants.HEADER_SERVER);
		for (ServletContextInitializer initializer : initializers) {
			try {
				initializer.onStartup(context);
			} catch (ServletException e) {
				throw new NettyServerException(e);
			}
		}
		//从SpringBoot配置中获取端口，如果没有则随机生成
		int port = getPort() > 0 ? getPort() : new Random().nextInt(65535 - 1024) + 1024;
		//nettyservlet工作线程,默认128s
		nProcessors = (nProcessors == null ? ServerOptions.WORKER_THREADS : nProcessors);
		//超时时间，默认30s
		timeout = (timeout == null ? ServerOptions.TIMEOUT : timeout);
		NettyChannelInitializer nettyChannelInitializer = HandlerInitSelector.getHandlers(Protocol.SERVLET, nProcessors, timeout, context);
		return new NettyContainer(port, nettyChannelInitializer, context); //初始化容器并返回
	}
}
